package com.ddfeiyu.server;


import com.ddfeiyu.agreement.codec.ObjDecoder;
import com.ddfeiyu.agreement.codec.ObjEncoder;
import com.ddfeiyu.redis.util.RedisQueueUtil;
import com.ddfeiyu.server.handler.LogHandler;
import com.ddfeiyu.server.properties.ServerProperties;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.net.InetSocketAddress;
import java.util.concurrent.Callable;

@Service("nettyServer")
public class NettyServer implements Callable<Channel> {

    private Logger logger = LoggerFactory.getLogger(NettyServer.class);

    @Autowired
    private ServerProperties serverProperties;

    private final EventLoopGroup parentGroup = new NioEventLoopGroup(2);
    private final EventLoopGroup childGroup = new NioEventLoopGroup();
    private Channel channel;

    @Autowired
    private RedisQueueUtil redisQueueUtil;

    @Override
    public Channel call() throws Exception {
        ChannelFuture channelFuture = null;

        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(parentGroup, childGroup).
                    //非阻塞模式
                    channel(NioServerSocketChannel.class).
                    option(ChannelOption.SO_BACKLOG, 128).
                    childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                    ChannelPipeline pipeline = ch.pipeline();
                    pipeline.addLast(new ObjDecoder());
                    // 在管道中添加我们自己的接收数据实现方法
                    pipeline.addLast(new LogHandler(redisQueueUtil));
                    pipeline.addLast(new ObjEncoder());
                }
            });
            channelFuture = bootstrap.bind(new InetSocketAddress(serverProperties.getPort())).syncUninterruptibly();
            this.channel = channelFuture.channel();
        }catch (Exception e){
            logger.error("NettyServer start error", e.getMessage());
        } finally {
            if (null != channelFuture && channelFuture.isSuccess()) {
                logger.info("NettyServer start done. ");
            } else {
                logger.error("NettyServer start error. ");
            }
        }
        return channel;
    }



    public void destroy() {
        if (null == channel) {
            return;
        }
        channel.close();
        parentGroup.shutdownGracefully();
        childGroup.shutdownGracefully();
    }

    public boolean isActive(){
        return channel.isActive();
    }

    public Channel channel() {
        return channel;
    }

}
